// WMITESTS.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <iostream>
#include <wbemidl.h>
#include <conio.h>
#include <Windows.h>
#include <string>
#include <vector>
#include <sstream>
#include <stdlib.h>
#include <fstream>
//#include <vld.h> //find memory leaks

using namespace std;

# pragma comment(lib, "wbemuuid.lib")
IWbemServices *wmiSvc;
IWbemLocator *pLoc;



std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {
    std::stringstream ss(s);
    std::string item;
    while(std::getline(ss, item, delim)) {
        elems.push_back(item);
    }
    return elems;
}

std::vector<std::string> split(const std::string &s, char delim) {
    std::vector<std::string> elems;
    return split(s, delim, elems);
}

void stringToUnicode(wchar_t * p,const std::string& str){
	int len;
	int slength = (int)str.length() + 1;
	len = MultiByteToWideChar(CP_ACP, 0, str.c_str(), slength, 0, 0);
	MultiByteToWideChar(CP_ACP, 0, str.c_str(), slength, p, len);
}

const std::string wchartToStr(const wchar_t* wInput)
{
   std::string sOutput = "";
   size_t* nbOfChar = new size_t; 
   char* cOut = new char[1023];
   size_t sizeInBytes = 1023;

   wcstombs_s( nbOfChar, cOut, sizeInBytes, wInput, 1023);
   sOutput += cOut;

   delete [] cOut;
   delete nbOfChar;

   return sOutput;
}

template <typename T>
inline std::string to_string (const T& t)
{
    std::stringstream ss;
    ss << t;
    return ss.str();
}

std::string ExecQuerySync(std::string, std::string );
std::string ExecMultiQuery(vector<std::string> vect, vector<std::string> commaSep){
	std::string rezult = "";
	std::vector<std::string>::iterator itComma = commaSep.begin();
	std::vector<std::string>::iterator it = vect.begin();
	for( ; (it != vect.end()) && (itComma != commaSep.end()) ; ++it, ++itComma) {
		rezult += ExecQuerySync(*it,*itComma);
		rezult += "/";
	}
	return rezult;
}

std::string ExecQuerySync(std::string query, std::string commaSeparated)
{

	ofstream out("D:\\x.txt",std::ios::app);

	out<<"1"<<endl;

    BSTR Language = SysAllocString(L"WQL");
	out<<"2"<<endl;
	wchar_t * queryBuffer = new wchar_t[query.size() + 1];
	out<<"3"<<endl;
	stringToUnicode(queryBuffer, query);
	out<<"4"<<endl;
    BSTR Query = SysAllocString(queryBuffer);
	out<<"5"<<endl;
	delete [] queryBuffer;
    IEnumWbemClassObject *pEnum = 0;
	out<<"6"<<endl;
    // Issue the query.

	if(Language == NULL){
		out<<"Language null"<<endl;
	}
	if(Query == NULL){
		out<<"Query null"<<endl;
	}
    HRESULT hRes = wmiSvc->ExecQuery(
        Language,
        Query,
        WBEM_FLAG_FORWARD_ONLY,         // Flags
        0,                              // Context
        &pEnum
        );
    SysFreeString(Query);
    SysFreeString(Language);
	out<<"7"<<endl;
    if (hRes != 0)
    {
        printf("Error\n");
        return "";
    }
	out<<"8"<<endl;
    ULONG uTotal = 0;
	std::string result = "";
    // Retrieve the objects in the result set.
	out<<"9"<<endl;
    for (;;)
    {
        IWbemClassObject *pObj = 0;
        ULONG uReturned = 0;
        hRes = pEnum->Next(0,1,&pObj,&uReturned);
        uTotal += uReturned;

        if (uReturned == 0L)
            break;
		std::vector<std::string> commaAtoms = split(commaSeparated,',');
		for(std::vector<std::string>::iterator it = commaAtoms.begin(); it != commaAtoms.end(); ++it) {
			wchar_t * retConv = new wchar_t[(*it).size() + 1];
			stringToUnicode(retConv,*it);
			BSTR x = SysAllocString(retConv);
			//delete [] retConv;

			VARIANT v;
			HRESULT hr;
			hr = pObj->Get(x, 0, &v, 0, 0);
			if (SUCCEEDED(hr)){
				result += wchartToStr(x);
				result += ";";
				switch(V_VT(&v)){
					case VT_BSTR:				
						result += wchartToStr(v.bstrVal);
						break;
					case VT_NULL:
						result += "";
						break;
					case VT_I4:
						result += to_string(v.lVal);
						break;
					case VT_UI4:
						result += to_string(v.ulVal);
						break;
					case VT_R4:
						result += to_string(v.fltVal);
						break;
					case VT_R8:
						result += to_string(v.dblVal);
						break;
					case VT_BOOL:
						result += to_string(v.boolVal);
						break;					
					case VT_I1:
						result += to_string(v.cVal);
						break;
					case VT_UI1:
						result += to_string(v.bVal);
						break;
					case VT_I2:
						result += to_string(v.iVal);
						break;
					case VT_UI2:
						result += to_string(v.uiVal);
						break;
					case VT_I8:
						result += to_string(v.llVal);
						break;
					case VT_UI8:
						result += to_string(v.ullVal);
						break;
					case VT_INT:
						result += to_string(v.intVal);
						break;
					case VT_UINT:
						result += to_string(v.uintVal);
						break;
					default:
						break;
				}
				result += "\r\n";
			}
			VariantClear(&v);
			SysFreeString(x);
		}
        pObj->Release();    // Release objects not owned.            
    }
    // All done.
    pEnum->Release();
	return result;
}

int initWMI(){
	HRESULT hr;
	hr = CoInitializeEx(0, COINIT_MULTITHREADED); 
	if (FAILED(hr)) 
	{ cout << "Failed to initialize COM library. Error code = 0x"
		   << hex << hr << endl; 
	  return -1;
	}

	hr =  CoInitializeSecurity(
    NULL,                      // Security descriptor    
    -1,                        // COM negotiates authentication service
    NULL,                      // Authentication services
    NULL,                      // Reserved
    RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication level for proxies
    RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation level for proxies
    NULL,                        // Authentication info
    EOAC_NONE,                   // Additional capabilities of the client or server
    NULL);                       // Reserved

	if (FAILED(hr))
	{
	   CoUninitialize();
	   return -1;                  // Program has failed.
	}

	pLoc = 0;

    hr = CoCreateInstance(CLSID_WbemLocator, 0, 
        CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID *) &pLoc);
 
    if (FAILED(hr))
    {
        CoUninitialize();
        return -1;     // Program has failed.
    }
	IWbemServices *pSvc = 0;

	hr = pLoc->ConnectServer(
	    L"ROOT\\CIMV2", 
        NULL,
        NULL,
        0,
		NULL,
		0,
		0, 
		&pSvc
        );
    
    if (FAILED(hr))
    {
        pLoc->Release();     
        CoUninitialize();
        return -1;                // Program has failed.
    }

    // Set the proxy so that impersonation of the client occurs.
    hr = CoSetProxyBlanket(pSvc,
       RPC_C_AUTHN_WINNT,
       RPC_C_AUTHZ_NONE,
       NULL,
       RPC_C_AUTHN_LEVEL_CALL,
       RPC_C_IMP_LEVEL_IMPERSONATE,
       NULL,
       EOAC_NONE
    );

    if (FAILED(hr))
    {
       pSvc->Release();
      pLoc->Release();     
        CoUninitialize();
        return -1;      // Program has failed.
    }

	wmiSvc = pSvc;

	return 0;
}

void release(){
	wmiSvc->Release();
    pLoc->Release();
    CoUninitialize();
}

int _tmain(int argc, _TCHAR* argv[])
{
	

	//hereweConsume Data

	initWMI();
		string query = "SELECT ";
		query += "IODataOperationsPerSec,IOOtherOperationsPerSec,IOReadOperationsPerSec,IOWriteOperationsPerSec,IOReadBytesPerSec,IOWriteBytesPerSec,IOOtherBytesPerSec,IOWriteOperationsPerSec,IODataBytesPerSec,Timestamp_Sys100NS";
		query += " FROM Win32_PerfRawData_PerfProc_Process WHERE IDProcess = ";
		char buffer[10];
		query += itoa(1728,buffer,10);
		vector<std::string> vect;
		vect.push_back(query);

		vector<std::string> vectComma;
		vectComma.push_back("IODataOperationsPerSec,IOOtherOperationsPerSec,IOReadOperationsPerSec,IOWriteOperationsPerSec,IOReadBytesPerSec,IOWriteBytesPerSec,IOOtherBytesPerSec,IOWriteOperationsPerSec,IODataBytesPerSec,Timestamp_Sys100NS");

		cout<<ExecMultiQuery(vect,vectComma);

	cout<<query;
	release();
	getch();
	return 0;
}

